﻿using ReadWriteCsv;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace StockAnomalyDetector
{
    class Autodetector
    {
        //private double[] sliceVector = new double[6];  // available？，时间，均值，方差，偏离系数，峰度系数
        private double[] hoursVector = new double[4];  // 均值，方差，偏离系数，峰度系数
        private double[][] vectors = new double[12][]; // 装载一个小时内12个向量
        private int sliceCount = 0;
        private List<int> time = new List<int>();
        private List<double> deviation = new List<double>();

        // 格式 股票代码，日期，偏离程度^偏离出现时间|偏离程度^偏离出现时间.....
        public static List<string> exceptionList = new List<string>() { "stockCode,date,div^time|" };
        public static CsvFileWriter writer = new CsvFileWriter(@"D:\股票数据\" + "AutoDetector" + ".csv");

        private List<double> slicePrice = new List<double>();
        private List<double> hourPrice = new List<double>();

        public Autodetector()
        {
            for (int i = 0; i < 12; i++)
                vectors[i] = new double[6];
            resetVectors();
        }

        public void update(double price)
        {
            slicePrice.Add(price);
            hourPrice.Add(price);
        }

        public void analyzeSlice(Clock endTime)
        {
            // update vector
            if (slicePrice.Count > 99)
            {
                double[] vec = GetVector(slicePrice);
                vectors[sliceCount][0] = 1;
                vectors[sliceCount][1] = endTime.turnBackToInt();
                vectors[sliceCount][2] = vec[0];
                vectors[sliceCount][3] = vec[1];
                vectors[sliceCount][4] = vec[2];
                vectors[sliceCount][5] = vec[3];
            }
            

            if (sliceCount == 11)
            {
                // 当积累了一个小时的vector时，开始执行小时分析并reset所有向量
                analyzeHour();
                sliceCount = 0;
                resetVectors();
                hourPrice.Clear();
            }
            else
                sliceCount++;

            // reset slicePrice
            slicePrice.Clear();
        }

        private void resetVectors()
        {
            for(int i = 0;i<12;i++)
                vectors[i][0] = -1;
        }

        private double compareWithHour(double[] sliceVector)
        {
            if (sliceVector[0] == -1)
                return 1000;
            else
            {
                double pointProduct = sliceVector[2] * hoursVector[0] + sliceVector[3] * hoursVector[1] + sliceVector[4] * hoursVector[2] + sliceVector[5] * hoursVector[3];
                return pointProduct / 10000;
            }
        }

        

        public void analyzeHour()
        {
            // compare 
            hoursVector = GetVector(hourPrice);

            IEnumerable<double[]> result = 
                         from v in vectors
                         where compareWithHour(v)<0.85//偏离角度大于30°
                         orderby compareWithHour(v) descending
                         select v;
            //hunt for error
            List<double[]> resultList = result.ToList();
            // 只在数量足够多的时候狩猎
            if(resultList.Count>=4)
            {
                double first = 0;
                double second = 0;
                double third = 0;
                double fourth = 0;
                double mode;
                // 求和模长于模长和之比
                foreach(double[] v in resultList)
                {
                    first += v[2];
                    second += v[3];
                    third += v[4];
                    fourth += v[5];
                }
                mode = Math.Sqrt(first * first + second * second + third * third + fourth * fourth);
                if (mode / 100 * resultList.Count >0.9999)
                {
                    foreach(double[] v in resultList)
                    {
                        time.Add(Convert.ToInt32(v[1]));
                        deviation.Add(compareWithHour(v));                
                    }
                }
            }
            // reset slice count and vectors
        }

        public void analyzeRecord(string sourceName)
        {
            StringBuilder s = new StringBuilder();
            if (time.Count > 0)
            {
                s.Append(Convert.ToString(Regex.Match(sourceName, @"[A-Z]{2}\d{6}")) + ",");
                s.Append(Convert.ToString(Regex.Match(sourceName, @"\d{8}"))+",");
                for (int i = 0; i < time.Count; i++)
                {
                   
                    s.Append(string.Format("{0:0.00}",deviation[i]));
                    s.Append("^");
                    s.Append(time[i]);
                    s.Append("|");
                }
                exceptionList.Add(s.ToString());
                Console.WriteLine("Autodetector has caught someting");
            }
        }

        static double[] GetVector(List<double> prices)
        {
            // 目标模长
            double norm = 100;

            // 样本容量
            int n = prices.Count;

            // 均值
            double avg = prices.Average();

            // 方差
            double vari = 0;
            foreach (var price in prices)
            {
                vari += Math.Pow(price - avg, 2);
            }
            vari /= n;
            double s = Math.Sqrt(vari); // 标准差

            double dev = 0; // 偏差系数
            double k = 0; // 峰度系数
            foreach (var price in prices)
            {
                dev += Math.Pow(price - avg, 3);
                k += Math.Pow(price - avg, 4);
            }
            dev /= Math.Pow(s, 3);
            k /= n * Math.Pow(vari, 2);

            // 我怀疑偏差系数有问题
            dev = 0;

            double normsquare = avg * avg + vari * vari + dev * dev + k * k;
            double ratio = Math.Sqrt(norm * norm / normsquare);
            double[] vector = new double[] { avg * ratio, vari * ratio, dev * ratio, k * ratio };

            return vector;
        }

    }
}
